package com.jxauaia.contest.security;

import com.jxauaia.contest.security.JwtTokenProvider;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;

@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {

    private static final Logger logger = LoggerFactory.getLogger(JwtAuthenticationFilter.class);

    // 定义公开路径列表
    private static final List<String> PUBLIC_PATHS = Arrays.asList(
            "/auth/login",
            "/auth/register",
            "/auth/captcha",
            "/public/",
            "/uploads/",
            "/swagger-ui",
            "/v3/api-docs"
    );

    @Autowired
    private JwtTokenProvider jwtTokenProvider;

    @Autowired
    private UserDetailsService userDetailsService;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
            throws ServletException, IOException {
        // 检查请求路径是否为公开路径
        String uri = request.getRequestURI();
        if (isPublicPath(uri)) {
            logger.debug("请求路径为公开路径，跳过认证: {}", uri);
            chain.doFilter(request, response);
            return;
        }

        final String requestTokenHeader = request.getHeader("Authorization");

        String username = null;
        String jwtToken = null;

        // JWT Token格式为 "Bearer token"，移除Bearer部分
        if (requestTokenHeader != null && requestTokenHeader.startsWith("Bearer ")) {
            jwtToken = requestTokenHeader.substring(7);
            try {
                username = jwtTokenProvider.getUsernameFromToken(jwtToken);
                logger.debug("从JWT令牌中解析出用户名: {}", username);
            } catch (Exception e) {
                logger.error("无法解析JWT令牌: {}", jwtToken, e);
                chain.doFilter(request, response);
                return;
            }
        } else {
            logger.warn("JWT令牌不是以Bearer开头或为空: {}", requestTokenHeader);
            chain.doFilter(request, response);
            return;
        }

        // 验证令牌
        if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
            try {
                UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);

                // 如果令牌有效，则配置Spring Security使用该令牌
                if (jwtTokenProvider.validateToken(jwtToken, userDetails)) {
                    UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
                            userDetails, null, userDetails.getAuthorities());
                    authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                    SecurityContextHolder.getContext().setAuthentication(authentication);
                    logger.info("用户 {} 认证成功", username);
                } else {
                    logger.warn("JWT令牌无效: {}", jwtToken);
                }
            } catch (Exception e) {
                logger.error("加载用户详情时出错: {}", username, e);
            }
        } else {
            logger.warn("未找到有效的用户名或已认证: {}", username);
        }
        chain.doFilter(request, response);
    }

    // 判断是否为公开路径
    private boolean isPublicPath(String uri) {
        // 添加更详细的日志，帮助调试
        logger.info("检查路径是否公开: {}", uri);

        // 移除/api前缀（如果有）
        String normalizedUri = uri;
        if (uri.startsWith("/api")) {
            normalizedUri = uri.substring(4);
        }

        // 检查是否匹配任何公开路径
        boolean isPublic = false;
        for (String publicPath : PUBLIC_PATHS) {
            if (normalizedUri.startsWith(publicPath)) {
                isPublic = true;
                break;
            }
        }

        // 记录判断结果
        logger.info("路径 {} 是否公开: {}", uri, isPublic);
        return isPublic;
    }
}